﻿using System;
using System.ComponentModel;
using Sinacor.Infra.UI.Common;
using Sinacor.Infra.Common.Exceptions;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Sinacor.UI.Bovespa.Ordens.Presenter
{
    /// <summary>
    /// Presenter Class - AjusteMercadoFuturoPresenter
    /// </summary>
    public class AjusteMercadoFuturoPresenter : BasePresenter<IBaseView>
    {
        #region Construtor

        /// <summary>
        /// Construtor
        /// </summary>
        /// <param name="view">View</param>
        public AjusteMercadoFuturoPresenter(IAjusteMercadoFuturo view)
            : base((IBaseView)view)
        {
            this._view = view;
            this.CalendarioPregao = new ModelCollection<Sinacor.UI.Bovespa.Ordens.Model.Calendario>();
            this.Filtro = new Sinacor.UI.Bovespa.Ordens.Model.Parameter.FiltroAjusteMercadoFuturo();
            this.ListaAjusteMercadoFuturo = new ModelCollection<Sinacor.UI.Bovespa.Ordens.Model.AjusteMercadoFuturo>();
            this._communicationControleMovimentoOrdens = new Sinacor.UI.Bovespa.Ordens.Communication.ControleMovimentoOrdens(this.Session);
        }

        #endregion

        #region Variáveis

        private IAjusteMercadoFuturo _view;
        private ModelCollection<Model.Calendario> _calendarioPregao;
        private Communication.AjusteMercadoFuturoCommunication _communicationAjusteMercadoFuturo;
        private Communication.Calendario _communicationCalendario;
        private Communication.Titulo _communicationTitulo;
        private Communication.ControleMovimentoOrdens _communicationControleMovimentoOrdens;
        private Model.Parameter.FiltroAjusteMercadoFuturo _filtro;
        private ModelCollection<Model.AjusteMercadoFuturo> _listaAjusteMercadoFuturo;
        private Model.InformacoesMovimento _informacoesMovimento;

        #endregion

        #region Propriedades

        /// <summary>
        /// Armazena o calendário do pregão que será apresentado no combobox na inserção de um ajuste
        /// </summary>
        public ModelCollection<Model.Calendario> CalendarioPregao
        {
            get { return _calendarioPregao; }
            set { _calendarioPregao = value; }
        }

        /// <summary>
        /// Propriedade para realizar binding no XAML e armazenar os filtros de pesquisa
        /// </summary>
        public Model.Parameter.FiltroAjusteMercadoFuturo Filtro
        {
            get { return _filtro; }
            set { _filtro = value; }
        }

        /// <summary>
        /// Armazena a lista de dados que irá aparecer no DataGrid
        /// </summary>
        public ModelCollection<Model.AjusteMercadoFuturo> ListaAjusteMercadoFuturo
        {
            get { return _listaAjusteMercadoFuturo; }
            set
            {
                _listaAjusteMercadoFuturo = value;
                if (value != null)
                {
                    ListaAjusteMercadoFuturo.EnableStateControl = true;
                }
            }
        }

        #endregion

        #region Métodos Públicos

        /// <summary>
        /// Realiza o UpdateTarget no SinacorTextBox do Ativo na pesquisa
        /// </summary>
        /// <param name="titulo"></param>
        public void AtualizarTituloEscolhido(Model.Titulo titulo)
        {
            if (titulo != null)
            {
                this._filtro.CodigoNegociacao = titulo.Codigo;
                this._view.ExibirTituloEscolhido();
            }
        }

        /// <summary>
        /// Realiza o Ajuste de Posição
        /// </summary>
        public void AjustarPosicao()
        {
            if (this._filtro.DataPregao == null)
                this._view.ExibirMensagem("Bovespa.Ordens.ExceptionMessage.DataPregaoAjustePosicao");
            else
            {
                if (this._view.ConfirmarAjustePosicao())
                {
                    try
                    {
                        this._communicationAjusteMercadoFuturo = new Communication.AjusteMercadoFuturoCommunication(this.Session);
                        this._communicationAjusteMercadoFuturo.AjustarPosicao((DateTime)this._filtro.DataPregao);
                        this._view.ExibirMensagem("Bovespa.Ordens.Message.OperacaoRealizadaSucesso");
                    }
                    catch (Exception ex)
                    {
                        HandleException(ex);
                    }
                }
            }
        }

        /// <summary>
        /// Calcula a variação do ajuste anterior
        /// </summary>
        /// <param name="request">Model AjusteMercadoFuturo</param>
        public void CalcularVariacaoAjusteAnterior(Model.AjusteMercadoFuturo request)
        {
            decimal? ajusteAplicado;
            ajusteAplicado = request.ValorAjusteAtual - request.ValorAjusteAnterior;
            this._view.ApresentarVariacao((decimal)ajusteAplicado, this.CalcularPercentualVariacao((decimal)ajusteAplicado, request.ValorAjusteAnterior.Value));
        }

        /// <summary>
        /// Calcula a variação do ajuste atual
        /// </summary>
        /// <param name="request">Model AjusteMercadoFuturo</param>
        public void CalcularVariacaoAjusteAtual(Model.AjusteMercadoFuturo request)
        {
            decimal? ajusteAplicado;
            ajusteAplicado = request.ValorAjusteAtual - request.ValorAjusteAnterior;
            this._view.ApresentarVariacao((decimal)ajusteAplicado, this.CalcularPercentualVariacao((decimal)ajusteAplicado, request.ValorAjusteAnterior.Value));
        }

        /// <summary>
        /// Realiza pesquisa de ajustes de mercado futuro
        /// </summary>
        public void ConsultarAjustesMercadoFuturo()
        {
            try
            {
                this.ListaAjusteMercadoFuturo.Clear();

                this._communicationAjusteMercadoFuturo = new Communication.AjusteMercadoFuturoCommunication(this.Session);
                ModelCollection<Model.AjusteMercadoFuturo> response = this._communicationAjusteMercadoFuturo.ConsultarMercadoFuturo(this._filtro);

                if (response != null && response.Count != 0)
                {
                    this.ListaAjusteMercadoFuturo = response;
                    this._view.ApresentarListaAjustesMercadoFuturo();
                }
                else
                    this._view.ExibirMensagem("Bovespa.Cliente.ExceptionMessage.PesquisaSemResultado");
            }
            catch (Exception ex)
            {
                HandleException(ex);
            }
        }

        /// <summary>
        /// Consulta informações do movimento
        /// </summary>
        public void ConsultarInformacoesMovimento()
        {
            if (this._communicationControleMovimentoOrdens != null)
                this._informacoesMovimento = this._communicationControleMovimentoOrdens.ObterInformacoesMovimento(new Model.DataMovimento());
        }

        /// <summary>
        /// Realiza consulta ao calendário de pregões
        /// </summary>
        public void ConsultarCalendarioPregao()
        {
            try
            {
                this._communicationCalendario = new Sinacor.UI.Bovespa.Ordens.Communication.Calendario(this.Session);
                this.CalendarioPregao = this._communicationCalendario.ConsultarCalendario();
                this._view.ApresentarListaDataPregao();
            }
            catch (Exception ex)
            {
                HandleException(ex);
            }
        }

        /// <summary>
        /// Verifica se movimento está aberto
        /// </summary>
        public void VerificarMovimento()
        {
            if (this._informacoesMovimento != null)
            {
                if (this._informacoesMovimento.EstadoMovimento != Sinacor.UI.Bovespa.Ordens.Model.Enum.TipoMovimento.Abertura)
                {
                    this._view.InformarMovimentoFechado();
                }
            }
        }

        /// <summary>
        /// Carrega Model com o calendário de pregões
        /// </summary>
        public void Inicializar()
        {
            this.ConsultarCalendarioPregao();
            this.ConsultarInformacoesMovimento();
            this.VerificarMovimento();
        }

        /// <summary>
        /// Realiza Consulta de Ativos
        /// </summary>
        /// <returns></returns>
        public Model.Titulo ObterTitulo()
        {
            Model.Titulo tituloRequest = new Model.Titulo();
            tituloRequest.Codigo = _filtro.CodigoNegociacao;
            tituloRequest.DataPregao = _filtro.DataPregao;

            try
            {
                this._communicationTitulo = new Sinacor.UI.Bovespa.Ordens.Communication.Titulo(this.Session);
                Model.Titulo tituloResponse = this._communicationTitulo.ObterTitulo(tituloRequest);

                if (tituloResponse == null)
                    //Informa o usuário que o título não está cadastrado
                    this._view.ExibirMensagem("Bovespa.Ordens.ExceptionMessage.AtivoInexistente");
                else
                    return tituloResponse;
            }
            catch (Exception ex)
            {
                HandleException(ex);
            }

            return null;
        }        

        /// <summary>
        /// Salva registros de ajustes de mercado futuro
        /// </summary>
        public void Salvar()
        {
            ModelCollection<Model.AjusteMercadoFuturo> listaExclusao = this._listaAjusteMercadoFuturo.GetDeleted();
            ModelCollection<Model.Parameter.FiltroAjusteMercadoFuturo> filtroExclusao = new ModelCollection<Model.Parameter.FiltroAjusteMercadoFuturo>();
            Model.Parameter.FiltroAjusteMercadoFuturo itemFiltroExclusao;

            foreach (Model.AjusteMercadoFuturo item in listaExclusao)
            {
                itemFiltroExclusao = new Model.Parameter.FiltroAjusteMercadoFuturo();

                itemFiltroExclusao.CodigoNegociacao = item.CodigoNegociacao;
                itemFiltroExclusao.DataPregao = item.DataPregao;

                filtroExclusao.Add(itemFiltroExclusao);
            }
            try
            {
                this._communicationAjusteMercadoFuturo = new Communication.AjusteMercadoFuturoCommunication(this.Session);
                this._communicationAjusteMercadoFuturo.ExecutarTransacoes(this._listaAjusteMercadoFuturo.GetInserted(),
                                                                            this._listaAjusteMercadoFuturo.GetUpdated(),
                                                                            filtroExclusao);

                this._view.ExibirMensagem("Bovespa.Ordens.Message.OperacaoRealizadaSucesso");
            }
            catch (Exception ex)
            {
                HandleException(ex);
            }
        }

        /// <summary>
        /// Realiza validação da ativos
        /// </summary>
        /// <returns>True ou False</returns>
        public bool ValidarAtivo()
        {           
            Model.Titulo titulo = this.ObterTitulo();

            if (titulo != null && titulo.Mercado != Model.Enum.TipoMercado.Futuro)
            {
                this._view.InformarAtivoNaoPertenceMercadoFuturo();
                this._view.ApresentarDadosAtivo(0, 0);
            }
            else
            {
                if (titulo != null && titulo.FatorCotacao == null)
                {
                    this._view.ExibirMensagem("Bovespa.Ordens.ExceptionMessage.CodigoNegocioNaoPossuiFator");
                    this._view.ApresentarDadosAtivo(0, 0);
                }
                else if (titulo != null && titulo.FatorCotacao != null)
                {
                    this._view.ApresentarDadosAtivo((int)titulo.FatorCotacao, (decimal)titulo.PrecoExercido);
                    return true;
                }
                else if (titulo == null)
                {
                    this._view.ApresentarDadosAtivo(0, 0);
                    return false;
                }
            }

            return false;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public bool ValidarFiltroAtivo()
        {
            Model.Titulo titulo = this.ObterTitulo();

            if (titulo != null && titulo.Mercado != Model.Enum.TipoMercado.Futuro)
            {
                this._view.InformarAtivoNaoPertenceMercadoFuturo();
                return false;
            }
            else if (titulo == null)
                return false;
            else
                return true;
            
        }       

        /// <summary>
        /// Realiza validação do valor de ajuste anterior
        /// </summary>
        /// <param name="valor">Valor do ajuste anterior</param>
        /// <returns>True ou False</returns>
        public bool ValidarValorAjusteAnterior(Nullable<Decimal> valor)
        {
            if (valor == null || valor < 0)
            {
                this._view.InformarValorAjusteAnteriorObrigatorio();
                return false;
            }

            return true;
        }

        /// <summary>
        /// Realiza validação do valor de ajuste atual
        /// </summary>
        /// <param name="valor">Valor do ajuste atual</param>
        /// <returns>True ou False</returns>
        public bool ValidarValorAjusteAtual(Nullable<Decimal> valor)
        {
            if (valor == null || valor < 0)
            {
                this._view.InformarValorAtualObrigatorio();
                return false;
            }

            return true;
        }

        #endregion

        #region Métodos Privados

        /// <summary>
        /// Calcula o percentual de variação
        /// </summary>
        /// <param name="ajusteAplicado">Valor do ajuste aplicado</param>
        /// <param name="valorAjuste">Valor do ajuste</param>
        /// <returns>Variação</returns>
        private decimal CalcularPercentualVariacao(decimal ajusteAplicado, decimal valorAjuste)
        {
            decimal percentualVariacao = 0;
            if (valorAjuste > 0)
                percentualVariacao = (ajusteAplicado / valorAjuste) * 100;
            return percentualVariacao;
        }

        #endregion
    }
}